package lion.dev.encrypt;

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

/**
 * @author lion
 * @mail hl_0074@sina.com
 * @date 2011-12-28
 * @des 基于密码的加密,原理为： 1,跟据口令和盐生成密钥,加密数据 2,跟据密钥和盐生解密数据
 * @eg:
 */
public class PBE {

	public static final String ALGORITHM = "PBEWithMD5AndDES";
	public static final byte[] DEFAULT_SALT = { 1, 2, 3, 4, 5, 6, 7, 8 };

	public byte[] generateSalt(String seed) {

		SecureRandom sr = null;
		if (StringUtils.isNotBlank(seed)) {
			sr = new SecureRandom(seed.getBytes(Charsets.UTF_8));
		} else {
			sr = new SecureRandom();
		}

		return sr.generateSeed(8);
	}

	/**
	 * 用指定盐加密数据
	 */
	public byte[] encrypt(byte[] data, String password, byte[] salts) {

		return doFinal(Cipher.ENCRYPT_MODE, data, password, salts);
	}

	/**
	 * 用指定盐加密字符串
	 */
	public byte[] encrypt(String data, String password, byte[] salts) {

		return encrypt(data.getBytes(Charsets.UTF_8), password, salts);
	}

	/**
	 * 用默认盐加密数据
	 */
	public byte[] encrypt(byte[] data, String password) {

		return doFinal(Cipher.ENCRYPT_MODE, data, password, DEFAULT_SALT);
	}

	/**
	 * 用默认盐加密字符串
	 */
	public byte[] encrypt(String data, String password) {

		return encrypt(data, password, DEFAULT_SALT);
	}

	/**
	 * 用指定盐解密密数据
	 */
	public byte[] decrypt(byte[] data, String password, byte[] salts) {

		return doFinal(Cipher.DECRYPT_MODE, data, password, salts);
	}

	/**
	 * 用默认盐解密数据
	 */
	public byte[] decrypt(byte[] data, String password) {

		return decrypt(data, password, DEFAULT_SALT);
	}

	/**
	 * 用指定盐 解密数据，反回字符串
	 */
	public String decryptString(byte[] data, String password, byte[] salts) {

		return new String(decrypt(data, password, salts), Charsets.UTF_8);
	}

	/**
	 * 用默认盐 解密数据，反回字符串
	 */
	public String decryptString(byte[] data, String password) {

		return decryptString(data, password, DEFAULT_SALT);
	}

	/**
	 * 加解密
	 */
	private byte[] doFinal(int mode, byte[] data, String password, byte[] salt) {

		Key key = generateKey(password);
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 1000);

		byte[] result = null;
		try {
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(mode, key, paramSpec);
			result = cipher.doFinal(data);
		} catch (Exception e) {
			e.printStackTrace();
			result = new byte[0];
		}
		return result;
	}

	/**
	 * 生成密钥
	 */
	private SecretKey generateKey(String password) {

		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		SecretKey secretKey = null;
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
			secretKey = keyFactory.generateSecret(keySpec);
		} catch (Exception e) {
		}

		return secretKey;
	}

	public static void main(String[] args) {

		String src = "中华人民共和国";
		System.out.println("src:" + src);
		String password = "carry";

		PBE pbe = new PBE();
		String encrypted = Base64.encodeBase64String(pbe.encrypt(src, password));
		System.out.println("加密后：" + encrypted);
		System.out.println("解密：" + pbe.decryptString(Base64.decodeBase64(encrypted), password));

	}
}
